using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Text.Json.Serialization;

namespace AI.Model.Json.Chat;

/// <summary>
/// Chat completion request body model.
/// </summary>
[DataContract]
public class ChatRequestBody
{
    /// <summary>
    /// ID of the model to use. See the model endpoint compatibility table for details on which models work with the Chat API.
    /// </summary>
    /// <remarks>
    /// https://platform.openai.com/docs/models/model-endpoint-compatibility
    /// </remarks>
    [DataMember(Name = "model")]
    [JsonPropertyName("model")]
    public string? Model { get; set; }

    /// <summary>
    /// A list of messages comprising the conversation so far.
    /// </summary>
    [DataMember(Name = "messages")]
    [JsonPropertyName("messages")]
    public ChatMessage[]? Messages { get; set; }

    /// <summary>
    /// A list of functions the model may generate JSON inputs for.
    /// </summary>
    [DataMember(Name = "functions")]
    [JsonPropertyName("functions")]
    [JsonConverter(typeof(ChatFunctionsJsonConverter))]
    public object? Functions { get; set; }

    /// <summary>
    /// Controls how the model responds to function calls. "none" means the model does not call a function, and responds to the end-user. "auto" means the model can pick between an end-user or calling a function. Specifying a particular function via {"name":\ "my_function"} forces the model to call that function. "none" is the default when no functions are present. "auto" is the default if functions are present.
    /// </summary>
    [DataMember(Name = "function_call")]
    [JsonPropertyName("function_call")]
    public object? FunctionCall { get; set; }

    /// <summary>
    /// What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.
    /// </summary>
    /// <remarks>
    /// We generally recommend altering this or top_p but not both.
    /// </remarks>
    [DataMember(Name = "temperature")]
    [JsonPropertyName("temperature")]
    public decimal Temperature { get; set; } = 1;

    /// <summary>
    /// An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.
    /// </summary>
    /// <remarks>
    /// We generally recommend altering this or temperature but not both.
    /// </remarks>
    [DataMember(Name = "top_p")]
    [JsonPropertyName("top_p")]
    public decimal TopP { get; set; } = 1;

    /// <summary>
    /// How many chat completion choices to generate for each input message.
    /// </summary>
    [DataMember(Name = "n")]
    [JsonPropertyName("n")]
    public int N { get; set; } = 1;

    /// <summary>
    /// If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a data: [DONE] message.
    /// </summary>
    [DataMember(Name = "stream")]
    [JsonPropertyName("stream")]
    public bool Stream { get; set; }

    /// <summary>
    /// Up to 4 sequences where the API will stop generating further tokens.
    /// </summary>
    [DataMember(Name = "stop")]
    [JsonPropertyName("stop")]
    public string? Stop { get; set; }

    /// <summary>
    /// The maximum number of tokens to generate in the chat completion.
    /// </summary>
    /// <remarks>
    /// The total length of input tokens and generated tokens is limited by the model's context length.
    /// </remarks>
    [DataMember(Name = "max_tokens")]
    [JsonPropertyName("max_tokens")]
    public int MaxTokens { get; set; } = 16;

    /// <summary>
    /// Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.
    /// </summary>
    [DataMember(Name = "presence_penalty")]
    [JsonPropertyName("presence_penalty")]
    public decimal PresencePenalty { get; set; }

    /// <summary>
    /// Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.
    /// </summary>
    [DataMember(Name = "frequency_penalty")]
    [JsonPropertyName("frequency_penalty")]
    public decimal FrequencyPenalty { get; set; }

    /// <summary>
    /// Modify the likelihood of specified tokens appearing in the completion.
    /// </summary>
    /// <remarks>
    /// Accepts a json object that maps tokens (specified by their token ID in the tokenizer) to an associated bias value from -100 to 100. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token.
    /// </remarks>
    [DataMember(Name = "logit_bias")]
    [JsonPropertyName("logit_bias")]
    public Dictionary<string, decimal>? LogitBias { get; set; }

    /// <summary>
    /// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
    /// </summary>
    [DataMember(Name = "user")]
    [JsonPropertyName("user")]
    public string? User { get; set; }
}
